package com.vonchange.headb.core;

import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Map.Entry;
import java.util.concurrent.ConcurrentHashMap;

import com.vonchange.headb.core.base.HeaCore;
import com.vonchange.headb.core.bean.ColumnCondition;
import com.vonchange.headb.core.bean.Entity;
import com.vonchange.headb.core.bean.EntityField;
import com.vonchange.headb.core.bean.SelectColumn;
import com.vonchange.headb.core.bean.SqlFragment;
import com.vonchange.headb.core.bean.SqlParmeter;
import com.vonchange.headb.core.bean.TableSql;
import com.vonchange.headb.core.constant.HeaConstant;
import com.vonchange.headb.core.map.HeaMap;
import com.vonchange.headb.utils.bean.HBeanUtils;
import com.vonchange.headb.utils.map.HHashMap;
import com.vonchange.headb.utils.named.HNamedParameterUtils;
import com.vonchange.headb.utils.named.ParsedSql;
import com.vonchange.headb.utils.orm.HOrmUtil;
import com.vonchange.headb.utils.string.HStringUtils;
import com.vonchange.headb.utils.xml.HXmlUtils;

public abstract class HeaSoul<T> extends HeaCore<T> {
	/**
	 * 获取Id值
	 * @param entity
	 * @return Id值
	 */
	protected Object getId(T entity) {
		String entityName = getEntityName();
		Entity entityInfo = entityMap.get(entityName);
		 Object value =HBeanUtils.getProperty(entity, entityInfo.getIdFieldName());
		return value;
	}

	/**
	 * 生成插入Sql
	 * @param entity
	 * @return SqlParmeter
	 */
	protected SqlParmeter generateInsertSql(T entity) {
		initEntityInfo(this.entityType);
		SqlParmeter sqlParmeter = new SqlParmeter();
		List<String> columnList = new ArrayList<String>();
		List<Object> valueList = new ArrayList<Object>();
		String entityName = getEntityName();
		Entity entityInfo = entityMap.get(entityName);
		String tableName = entityInfo.getTableName();
		// 获得ID
		Integer idModel = entityInfo.getIdModel();
		if (idModel == HeaConstant.Entity.UUID) {
		//	columnList.add(entityInfo.getIdColumnName());
			String uuid = HStringUtils.uuid();
			//valueList.add(uuid);
			HBeanUtils.setProperty(entity, entityInfo.getIdFieldName(), uuid);
		}
		Map<String, EntityField> entityFieldMap = entityMap.get(entityName).getFieldMap();
		for (Entry<String, EntityField> entry : entityFieldMap.entrySet()) {
			String fieldName = entry.getKey();
			EntityField entityField = entry.getValue();
			if (entityField.getIsColumn()) {					
				 Object value =HBeanUtils.getPublicPro(entity, fieldName);
					if (null != value) {
						columnList.add("`"+entityField.getColumnName()+"`");
						valueList.add(value);
					}	
			}
		}
		String insertSql = HStringUtils.format("insert into {0}({1}) values ({2})", tableName, HStringUtils.StrList(columnList, ","), HStringUtils.StrNums("?", ",", columnList.size()));
		sqlParmeter.setIdModel(idModel);
		String idName = entityInfo.getIdFieldName();
		sqlParmeter.setIdName(idName);
		sqlParmeter.setSql(insertSql);
		sqlParmeter.setParameters(valueList.toArray());
		return sqlParmeter;
	}

	/**
	 * 生成根据Id查找语句
	 * @param id
	 * @return SqlParmeter
	 */
	protected SqlParmeter generateFindByIdSql(Object id) {
		initEntityInfo(this.entityType);
		SqlParmeter sqlParmeter = new SqlParmeter();
		String entityName = getEntityName();
		Entity entityInfo = entityMap.get(entityName);
		String tableName = entityInfo.getTableName();
		String idColumnName = entityInfo.getIdColumnName();
		String sql = HStringUtils.format("select  *  from {0} where {1}=?", tableName, idColumnName);
		sqlParmeter.setSql(sql);
		sqlParmeter.setParameters(new Object[] { id });
		return sqlParmeter;
	}

	/**
	 *生成查询sql
	 * @param parameter
	 * @return SqlParmeter
	 */
	protected SqlParmeter generateQuerySql(HeaMap parameter) {
		initEntityInfo(this.entityType);
		String entityName = getEntityName();
		Entity entityInfo = entityMap.get(entityName);
		String tableName = entityInfo.getTableName();
		SqlParmeter sqlParmeter = new SqlParmeter();
		if (null == parameter) {
			parameter = new HeaMap();
		}
		List<Object> params = new ArrayList<Object>();
		ConcurrentHashMap<String, Boolean> aliasMap = new ConcurrentHashMap<String, Boolean>();
		StringBuffer whereSql = new StringBuffer();// 包含where后面的sql语局
		String link = "where";// 第一个默认连接是where
		boolean firstQueryFlag = true;// 是否是第一个需查项
		List<String> orderSqlList = new ArrayList<String>();
		List<String> groupSqlList = new ArrayList<String>();
		for (Entry<String, ?> entry : parameter.entrySet()) {
			String key = entry.getKey();
			Object value = entry.getValue();
			key = filterKey(key);
			if (key.equals(HeaConstant.Instruction.ADDBEGINNUM)) {
				continue;
			}
			if (key.equals(HeaConstant.Instruction.ADDENDNUM)) {
				continue;
			}
			if (key.startsWith(HeaConstant.Instruction.ADDORDER)) {
				orderSqlList = getOrder(orderSqlList, value);
				continue;
			}
			if (key.startsWith(HeaConstant.Instruction.ADDGROUP)) {
				groupSqlList = getOrder(groupSqlList, value);
				continue;
			}
			ColumnCondition columnCondition = new ColumnCondition();
			columnCondition = analyzeKey(columnCondition, key, value);
			if (!columnCondition.getIfQuery()) {
				continue;
			}
			if (!firstQueryFlag) {
				link = columnCondition.getAndOr();
			}
			whereSql.append(HStringUtils.format(" {0} {1}", link, columnCondition.getSqlFragment()));
			if (null != columnCondition.getCookedValue()) {
				params.addAll(columnCondition.getCookedValue());
			}
			firstQueryFlag = false;
		}
		String whereSqlStr = whereSql.toString();
		String columnSqlStr = "t.*";
		String columnSqlId = parameter.getAddSelect();

		if (null != columnSqlId) {
			columnSqlStr = getXml().getColumn(columnSqlId);
			SelectColumn selectColumn = HOrmUtil.analyzeSelectColumn(columnSqlStr,getXml());
			columnSqlStr = selectColumn.getCookedColumnSql();
			Map<String, Boolean> aliasMapInColumn = selectColumn.getAliasMap();
			if (!aliasMapInColumn.isEmpty()) {
				aliasMap.putAll(aliasMapInColumn);
				Map<String, String> columnAliasMap = getColumnMappingAlias(aliasMapInColumn);
				sqlParmeter.setAliasMap(columnAliasMap);
			}
		}
		// group
		String groupSql = "";
		if (groupSqlList.size() > 0) {
			groupSql = " group by " + HStringUtils.StrList(groupSqlList, ",");
		}
		// orderSql
		String orderSql = "";
		if (orderSqlList.size() > 0) {
			orderSql = " order by " + HStringUtils.StrList(orderSqlList, ",");
		}
		String tempStr = HStringUtils.addStr(whereSqlStr, groupSql, orderSql);
		aliasMap.putAll(HOrmUtil.getAliasFromSql(tempStr));
		// 分析得到joinSql
		String joinSql = "";
		if (!aliasMap.isEmpty()) {
			HHashMap<Integer, String> joinSqlMap = new HHashMap<Integer, String>();
			analyzeAliasMap(aliasMap, joinSqlMap);
			joinSql = getJoinSql(joinSqlMap);
		}
		if (tableName.startsWith("hea")) {
			tableName = entityName;
		}
		String tableSqlStr = HStringUtils.format("{0} t {1}", tableName, joinSql);
		// 0:column 1:tableSql 2:where 3:group 4:order
		Map<String, Object> viewParams = parameter.getViewParams();
		TableSql tableSql = getTableSql(tableSqlStr, viewParams);
		tableSqlStr = tableSql.getTargetTableSql();
		List<Object> tableParams = tableSql.getParams();
		String sql = HStringUtils.format("select {0} from {1}  {2} {3} {4}", columnSqlStr, tableSqlStr, whereSqlStr, groupSql, orderSql);
		sqlParmeter.setSql(sql);
		tableParams.addAll(params);
		sqlParmeter.setParameters(tableParams.toArray());
		return sqlParmeter;
	}

	/**
	 *生成删除sql
	 * @param parameter
	 * @return SqlParmeter
	 */ 
	protected SqlParmeter generateDeleteSql(HeaMap parameter) {
		initEntityInfo(this.entityType);
		String entityName = getEntityName();
		Entity entityInfo = entityMap.get(entityName);
		String tableName = entityInfo.getTableName();
		SqlParmeter sqlParmeter = new SqlParmeter();
		if (null == parameter) {
			parameter = new HeaMap();
		}
		if (parameter.size() == 0) {
			throw new RuntimeException("必须传人参数！");
		}
		List<Object> params = new ArrayList<Object>();
		ConcurrentHashMap<String, Boolean> aliasMap = new ConcurrentHashMap<String, Boolean>();
		StringBuffer whereSql = new StringBuffer();// 包含where后面的sql语局
		String link = "where";// 第一个默认连接是where
		boolean firstQueryFlag = true;// 是否是第一个需查项
		List<String> groupSqlList = new ArrayList<String>();
		for (Entry<String, ?> entry : parameter.entrySet()) {
			String key = entry.getKey();
			Object value = entry.getValue();
			key = filterKey(key);
			if (key.startsWith(HeaConstant.Instruction.ADDGROUP)) {
				groupSqlList = getOrder(groupSqlList, value);
				continue;
			}
			ColumnCondition columnCondition = new ColumnCondition();
			columnCondition = analyzeKey(columnCondition, key, value);
			if (!columnCondition.getIfQuery()) {
				continue;
			}
			if (!firstQueryFlag) {
				link = columnCondition.getAndOr();
			}
			whereSql.append(HStringUtils.format(" {0} {1}", link, columnCondition.getSqlFragment()));
			if (null != columnCondition.getCookedValue()) {
				params.addAll(columnCondition.getCookedValue());
			}
			firstQueryFlag = false;
		}
		String whereSqlStr = whereSql.toString();
		String groupSql = "";
		if (groupSqlList.size() > 0) {
			groupSql = " group by " + HStringUtils.StrList(groupSqlList, ",");
		}
		String tempStr = HStringUtils.addStr(whereSqlStr, groupSql);
		aliasMap.putAll(HOrmUtil.getAliasFromSql(tempStr));
		// 分析得到joinSql
		String joinSql = "";
		if (!aliasMap.isEmpty()) {
			HHashMap<Integer, String> joinSqlMap = new HHashMap<Integer, String>();
			analyzeAliasMap(aliasMap, joinSqlMap);
			joinSql = getJoinSql(joinSqlMap);
		}
		String tableSqlStr = HStringUtils.format("{0} t {1}", tableName, joinSql);
		Map<String, Object> viewParams = parameter.getViewParams();
		TableSql tableSql = getTableSql(tableSqlStr, viewParams);
		tableSqlStr = tableSql.getTargetTableSql();
		List<Object> tableParams = tableSql.getParams();
		// 0:tableName 1:where
		String sql = HStringUtils.format("delete t from {0}  {1}", tableSqlStr, whereSqlStr);
		sqlParmeter.setSql(sql);
		tableParams.addAll(params);
		sqlParmeter.setParameters(tableParams.toArray());
		return sqlParmeter;
	}

	/**
	 *生成根据Id删除Sql
	 * @param id
	 * @return SqlParmeter
	 */
	protected SqlParmeter generateDeleteByIdSql(Object id) {
		initEntityInfo(this.entityType);
		SqlParmeter sqlParmeter = new SqlParmeter();
		String entityName = getEntityName();
		Entity entityInfo = entityMap.get(entityName);
		String tableName = entityInfo.getTableName();
		String idColumnName = entityInfo.getIdColumnName();
		String sql = HStringUtils.format("delete from {0} where {1}=?", tableName, idColumnName);
		sqlParmeter.setSql(sql);
		sqlParmeter.setParameters(new Object[] { id });
		return sqlParmeter;
	}
	/**
	 *生成更新实体Sql
	 * @param entity
	 * @param nullFields 可以更新为NULL值得字段
	 * @return  SqlParmeter
	 */
	protected SqlParmeter generateUpdateEntitySql(T entity,String... nullFields) {
		SqlParmeter sqlParmeter = new SqlParmeter();
		initEntityInfo(this.entityType);
		String entityName = getEntityName();
		Entity entityInfo = entityMap.get(entityName);
		String tableName = entityInfo.getTableName();
		String idColumnName=entityInfo.getIdColumnName();
		Object idValue=HBeanUtils.getProperty(entity, entityInfo.getIdFieldName());
		if(null==idValue){
			throw new RuntimeException("主键值为空！无法更新");
		}
		SqlFragment setSqlEntity =getUpdateSetSql(entity, entityInfo,nullFields);
		String setSql=setSqlEntity.getSql();
		List<Object> params= setSqlEntity.getParams();
		params.add(idValue);
		//0:tableName 1:setSql 2:idName
		String sql = HStringUtils.format("update {0} set {1} where {2}=?",tableName,setSql,idColumnName);
		sqlParmeter.setSql(sql);
		sqlParmeter.setParameters(params.toArray());
		return sqlParmeter;
	}
	/**
	 * 生成更新Sql
	 * @param entity
	 * @param parameter
	 * @return
	 */
	protected SqlParmeter generateUpdateSql(T entity, HeaMap parameter) {
		initEntityInfo(this.entityType);
		String entityName = getEntityName();
		Entity entityInfo = entityMap.get(entityName);
		String tableName = entityInfo.getTableName();
		SqlParmeter sqlParmeter = new SqlParmeter();
		if (null == parameter) {
			parameter = new HeaMap();
		}
		if (parameter.size() == 0) {
			throw new RuntimeException("必须传人参数！");
		}
		List<Object> params = new ArrayList<Object>();
		ConcurrentHashMap<String, Boolean> aliasMap = new ConcurrentHashMap<String, Boolean>();
		StringBuffer whereSql = new StringBuffer();// 包含where后面的sql语局
		String link = "where";// 第一个默认连接是where
		boolean firstQueryFlag = true;// 是否是第一个需查项
		List<String> groupSqlList = new ArrayList<String>();
		for (Entry<String, ?> entry : parameter.entrySet()) {
			String key = entry.getKey();
			Object value = entry.getValue();
			key = filterKey(key);
			if (key.startsWith(HeaConstant.Instruction.ADDGROUP)) {
				groupSqlList = getOrder(groupSqlList, value);
				continue;
			}
			ColumnCondition columnCondition = new ColumnCondition();
			columnCondition = analyzeKey(columnCondition, key, value);
			if (!columnCondition.getIfQuery()) {
				continue;
			}
			if (!firstQueryFlag) {
				link = columnCondition.getAndOr();
			}
			whereSql.append(HStringUtils.format(" {0} {1}", link, columnCondition.getSqlFragment()));
			if (null != columnCondition.getCookedValue()) {
				params.addAll(columnCondition.getCookedValue());
			}
			firstQueryFlag = false;
		}
		String whereSqlStr = whereSql.toString();
		String groupSql = "";
		if (groupSqlList.size() > 0) {
			groupSql = " group by " + HStringUtils.StrList(groupSqlList, ",");
		}
		String tempStr = HStringUtils.addStr(whereSqlStr, groupSql);
		aliasMap.putAll(HOrmUtil.getAliasFromSql(tempStr));
		// 分析得到joinSql
		String joinSql = "";
		if (!aliasMap.isEmpty()) {
			HHashMap<Integer, String> joinSqlMap = new HHashMap<Integer, String>();
			analyzeAliasMap(aliasMap, joinSqlMap);
			joinSql = getJoinSql(joinSqlMap);
		}
		String tableSqlStr = HStringUtils.format("{0} t {1}", tableName, joinSql);
		Map<String, Object> viewParams = parameter.getViewParams();
		TableSql tableSql = getTableSql(tableSqlStr, viewParams);
		tableSqlStr = tableSql.getTargetTableSql();
		List<Object> tableParams = tableSql.getParams();
		// 获得setSql
		SqlFragment setSqlEntity = getUpdateSetSql(entity, entityInfo, parameter.getUpdateNullMap());
		// 0:tableSql 1:setSql 2:where
		String sql = HStringUtils.format("update {0} set {1} {2}", tableSqlStr, setSqlEntity.getSql(), whereSqlStr);
		// String sql = StringUtils.format("delete t from {0}  {1}",
		// tableSqlStr, whereSqlStr);
		sqlParmeter.setSql(sql);
		tableParams.addAll(setSqlEntity.getParams());// set
		tableParams.addAll(params);
		sqlParmeter.setParameters(tableParams.toArray());
		return sqlParmeter;
	}

	private SqlFragment getUpdateSetSql(T entity, Entity entityInfo, Map<String, Boolean> updateNullMap) {
		SqlFragment sqlFragment = new SqlFragment();
		List<String> setColumnList = new ArrayList<String>();
		List<Object> params = new ArrayList<Object>();
		Map<String, EntityField> entityFieldMap = entityInfo.getFieldMap();
		for (Entry<String, EntityField> entry : entityFieldMap.entrySet()) {
			String fieldName = entry.getKey();
			EntityField entityField = entry.getValue();
			if (entityField.getIsColumn()) {
				if (!entityField.getIsId()) {
					 Object value =HBeanUtils.getProperty(entity, fieldName);

					if (null != value) {
						setColumnList.add(HStringUtils.format("t.{0} =?", entityField.getColumnName()));
						params.add(value);
					}
				}
			}
		}
		if (updateNullMap.size() > 0) {
			for (Entry<String, Boolean> entry : updateNullMap.entrySet()) {
				String fieldName = entry.getKey();
				String columnName = HOrmUtil.toSql(fieldName);
				setColumnList.add(HStringUtils.format("t.{0} =?", columnName));
				params.add(null);

			}
		}
		String sql = HStringUtils.StrList(setColumnList, ",");
		sqlFragment.setSql(sql);
		sqlFragment.setParams(params);
		return sqlFragment;
	}
	private SqlFragment getUpdateSetSql(T entity, Entity entityInfo,String... nullFields) {
		SqlFragment sqlFragment = new SqlFragment();
		List<String> setColumnList = new ArrayList<String>();
		List<Object> params = new ArrayList<Object>();
		Map<String, EntityField> entityFieldMap = entityInfo.getFieldMap();
		for (Entry<String, EntityField> entry : entityFieldMap.entrySet()) {
			String fieldName = entry.getKey();
			EntityField entityField = entry.getValue();
			if (entityField.getIsColumn()) {
				if (!entityField.getIsId()) {
					 Object value =HBeanUtils.getProperty(entity, fieldName);
					if (null != value) {
						setColumnList.add(HStringUtils.format("`{0}` =?", entityField.getColumnName()));
						params.add(value);
					}
				}
			}
		}
		if(null!=nullFields&&nullFields.length>0){
			for (String fieldStr : nullFields) {
				String columnName = HOrmUtil.toSql(fieldStr);
				setColumnList.add(HStringUtils.format("{0} =?", columnName));
				params.add(null);
			}
		}
		String sql = HStringUtils.StrList(setColumnList, ",");
		sqlFragment.setSql(sql);
		sqlFragment.setParams(params);
		return sqlFragment;
	}
	/**
	 *从xml获取可CUD的Sql
	 * @param updateSql
	 * @param parameter
	 * @return SqlParmeter
	 */
	protected SqlParmeter  generateCudSqlFromXml(String updateSql,HHashMap<String,Object> parameter){
		SqlParmeter sqlParmeter = new SqlParmeter();
		HXmlUtils xmlUtils= getXml();
		String updateSqlStr =xmlUtils.getUpdateSql(updateSql);
		updateSqlStr=getCUDSql(updateSqlStr);//替换heaview
		ParsedSql parsedSql = HNamedParameterUtils.parserSqlStatement(updateSqlStr);
		String sql = HNamedParameterUtils.substituteNamedParams(parsedSql, parameter);
		List<Object> params =HNamedParameterUtils.buildValueArray(parsedSql, parameter);
		sqlParmeter.setSql(sql);
		sqlParmeter.setParameters(params.toArray());
		return sqlParmeter;
	}
	/**
	 * 生成存储过程Sql
	 * @param procedureName
	 * @param paramNum
	 * @return 存储过程SQL
	 */
	protected String  generateProcedureSql(String procedureName,int paramNum){		
	    String sql=   HStringUtils.format("call {0}({1})", procedureName,HStringUtils.StrNums("?", ",", paramNum));
	    sql="{"+sql+"}"; 
	    return sql;
	 }
}
